/* Data Members */
double pos_dist{};
- OptionDouble distopt;
+ OptionDouble distopt{true};
OptionString arcfileopt;
OptionBool rteopt;
OptionBool trkopt;
QVector<arglist_t> args = {
{
- "file", &arcfileopt, "File containing vertices of arc",
+ "file", &arcfileopt, "File containing vertices of arc",
nullptr, ARGTYPE_FILE, ARG_NOMINMAX, nullptr
},
{
},
{
"distance", &distopt, "Maximum distance from arc",
- nullptr, ARGTYPE_ALLOW_TRAILING_DATA | ARGTYPE_STRING | ARGTYPE_REQUIRED, ARG_NOMINMAX, nullptr
+ nullptr, ARGTYPE_STRING | ARGTYPE_REQUIRED, ARG_NOMINMAX, nullptr
},
{
"exclude", &exclopt, "Exclude points close to the arc", nullptr,
* for "groups" of exactly one option. */
#define ARGTYPE_BEGIN_REQ 0x04000000U
#define ARGTYPE_END_REQ 0x02000000U
-/* For integer conversions specify the base to allow strict error checking and
- * proper conversion in Vecs */
-#define ARGTYPE_BASE_10 0x00000000U
-#define ARGTYPE_BASE_AUTO 0x00100000U
-#define ARGTYPE_BASE_16 0x00200000U
-
-/* For integer and double conversions is trailing data allowed?
- * This allows strict error checking in Vecs */
-#define ARGTYPE_ALLOW_TRAILING_DATA 0x00400000U
#define ARGTYPE_TYPEMASK 0x00000fffU
-#define ARGTYPE_BASEMASK 0x00300000U
#define ARGTYPE_FLAGMASK 0xfffff000U
#define ARG_NOMINMAX nullptr, nullptr
Vecs::free_options(flt->get_args());
}
-void FilterVecs::init_filter_vec(Filter* flt)
+void FilterVecs::init_filter_vec(Filter* flt, const QString& fltname)
{
QVector<arglist_t>* args = flt->get_args();
if (args && !args->isEmpty()) {
assert(args->isDetached());
+ for (auto& arg : *args) {
+ if (arg.argval != nullptr) {
+ arg.argval->reset();
+ QString id = QStringLiteral("%1(%2)").arg(fltname, arg.argstring);
+ arg.argval->init(id);
+ }
+ }
}
}
{
for (const auto& vec : d_ptr_->filter_vec_list) {
if (vec.vec != nullptr) {
- init_filter_vec(vec.vec);
+ init_filter_vec(vec.vec, vec.name);
}
}
}
static void prepare_filter(const fltinfo_t& fltdata);
fltinfo_t find_filter_vec(const QString& fltargstring);
static void free_filter_vec(Filter* flt);
- static void init_filter_vec(Filter* flt);
+ static void init_filter_vec(Filter* flt, const QString& fltname);
void init_filter_vecs();
static void exit_filter_vec(Filter* flt);
void exit_filter_vecs();
OptionBool snwhiteopt;
OptionString deficon;
OptionInt categoryopt;
- OptionInt categorybitsopt;
+ OptionInt categorybitsopt{false, 0};
OptionInt baudopt;
OptionString opt_codec;
int baud = 0;
},
{
"bitscategory", &categorybitsopt, "Bitmap of categories",
- nullptr, ARGTYPE_BASE_AUTO | ARGTYPE_INT, "1", "65535", nullptr
+ nullptr, ARGTYPE_INT, "1", "65535", nullptr
},
{
"baud", &baudopt, "Speed in bits per second of serial port (baud=9600)",
OptionBool opt_unique;
OptionBool opt_alerts;
OptionString opt_units;
- OptionDouble opt_speed;
- OptionDouble opt_proximity;
+ OptionDouble opt_speed{true};
+ OptionDouble opt_proximity{true};
OptionInt opt_sleep;
OptionString opt_lang;
OptionString opt_writecodec;
},
{
"proximity", &opt_proximity, "Default proximity",
- nullptr, ARGTYPE_ALLOW_TRAILING_DATA | ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+ nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr
},
{
"sleep", &opt_sleep, "After output job done sleep n second(s)",
},
{
"speed", &opt_speed, "Default speed",
- nullptr, ARGTYPE_ALLOW_TRAILING_DATA | ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+ nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr
},
{
"unique", &opt_unique, "Create unique waypoint names (default = yes)",
OptionInt gdb_opt_ver;
OptionBool gdb_opt_via;
OptionBool gdb_opt_roadbook;
- OptionInt gdb_opt_bitcategory;
+ OptionInt gdb_opt_bitcategory{false, 0};
OptionBool gdb_opt_drop_hidden_wpt;
int waypt_flag{};
},
{
"bitscategory", &gdb_opt_bitcategory, "Bitmap of categories",
- nullptr, ARGTYPE_BASE_AUTO | ARGTYPE_INT, "1", "65535", nullptr
+ nullptr, ARGTYPE_INT, "1", "65535", nullptr
},
{
"ver", &gdb_opt_ver,
void process() override;
private:
- OptionDouble addopt;
+ OptionDouble addopt{true};
OptionBool wgs84tomslopt;
double addf{};
// include static constexpr data member definitions with intializers for grid as private members.
QVector<arglist_t> args = {
{
"add", &addopt, "Adds a constant value to every altitude",
- nullptr, ARGTYPE_ALLOW_TRAILING_DATA | ARGTYPE_BEGIN_REQ | ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+ nullptr, ARGTYPE_BEGIN_REQ | ARGTYPE_STRING, ARG_NOMINMAX, nullptr
},
{
"wgs84tomsl", &wgs84tomslopt, "Converts WGS84 ellipsoidal height to orthometric height (MSL)",
OptionDouble opt_time;
double max_time_step{0};
- OptionDouble opt_dist;
+ OptionDouble opt_dist{true};
double max_dist_step{0};
OptionBool opt_route;
},
{
"distance", &opt_dist, "Distance interval",
- nullptr, ARGTYPE_END_EXCL | ARGTYPE_END_REQ | ARGTYPE_ALLOW_TRAILING_DATA | ARGTYPE_STRING,
+ nullptr, ARGTYPE_END_EXCL | ARGTYPE_END_REQ | ARGTYPE_STRING,
ARG_NOMINMAX, nullptr
},
{
start_session(ivecs.fmtname, fname);
if (ivecs.isDynamic()) {
ivecs.fmt = ivecs.factory(fname);
- Vecs::init_vec(ivecs.fmt);
+ Vecs::init_vec(ivecs.fmt, ivecs.fmtname);
Vecs::prepare_format(ivecs);
ivecs->rd_init(fname);
}
if (ovecs.isDynamic()) {
ovecs.fmt = ovecs.factory(ofname);
- Vecs::init_vec(ovecs.fmt);
+ Vecs::init_vec(ovecs.fmt, ovecs.fmtname);
Vecs::prepare_format(ovecs);
ovecs->wr_init(ofname);
}
if (filter.isDynamic()) {
filter.flt = filter.factory();
- FilterVecs::init_filter_vec(filter.flt);
+ FilterVecs::init_filter_vec(filter.flt, filter.fltname);
FilterVecs::prepare_filter(filter);
filter->init();
if (ivecs.isDynamic()) {
ivecs.fmt = ivecs.factory(fname);
- Vecs::init_vec(ivecs.fmt);
+ Vecs::init_vec(ivecs.fmt, ivecs.fmtname);
}
if (ovecs && ovecs.isDynamic()) {
ovecs.fmt = ovecs.factory(ofname);
- Vecs::init_vec(ovecs.fmt);
+ Vecs::init_vec(ovecs.fmt, ovecs.fmtname);
}
start_session(ivecs.fmtname, fname);
return parse_double(value_, id_, ok, end);
}
-void OptionInt::init(const QString& id, bool allow_trailing_data, int base)
+void OptionInt::init(const QString& id)
{
id_ = id;
- base_ = base;
- allow_trailing_data_ = allow_trailing_data;
}
void OptionInt::reset()
result_ = parse_integer(value_, id_, dieonerror, endp, base_);
}
+bool OptionInt::isValid(const QString& s) const
+{
+ bool ok;
+ QString end;
+ QString* endp = allow_trailing_data_? &end : nullptr;
+ (void) parse_integer(s, id_, &ok, endp, base_);
+ return ok;
+}
+
int OptionInt::get_result(QString* end) const
{
if (end != nullptr) {
return result_;
}
-void OptionDouble::init(const QString& id, bool allow_trailing_data, int /* base */)
+bool OptionInt::trailing_data_allowed() const
+{
+ return allow_trailing_data_;
+}
+
+void OptionDouble::init(const QString& id)
{
id_ = id;
- allow_trailing_data_ = allow_trailing_data;
}
void OptionDouble::reset()
result_ = parse_double(value_, id_, dieonerror, endp);
}
+bool OptionDouble::isValid(const QString& s) const
+{
+ bool ok;
+ QString end;
+ QString* endp = allow_trailing_data_? &end : nullptr;
+ (void) parse_double(s, id_, &ok, endp);
+ return ok;
+}
+
double OptionDouble::get_result(QString* end) const
{
if (end != nullptr) {
}
return result_;
}
+
+bool OptionDouble::trailing_data_allowed() const
+{
+ return allow_trailing_data_;
+}
[[nodiscard]] virtual bool has_value() const = 0;
[[nodiscard]] virtual bool isEmpty() const = 0;
[[nodiscard]] virtual const QString& get() const = 0;
- virtual void init(const QString& id, bool allow_trailing_data, int base) {}
+ virtual void init(const QString& id) {}
virtual void reset() = 0;
virtual void set(const QString& s) = 0;
return value_;
}
- void init(const QString& id, bool /* allow_trailing_data */, int /* base */) override
+ void init(const QString& id) override
{
id_ = id;
}
public:
/* Special Member Functions */
OptionInt() = default;
+ explicit OptionInt(bool allow_trailing_data, int base) :
+ allow_trailing_data_(allow_trailing_data),
+ base_(base)
+ {}
explicit(false) operator const QString& () const
{
return value_;
}
- void init(const QString& id, bool allow_trailing_data, int base) override;
+ void init(const QString& id) override;
void reset() override;
void set(const QString& s) override;
+ bool isValid(const QString& s) const;
int get_result(QString* end = nullptr) const;
+ bool trailing_data_allowed() const;
private:
QString value_;
QString id_;
int result_{};
QString end_;
- int base_{10};
bool allow_trailing_data_{false};
+ int base_{10};
};
class OptionDouble : public Option
public:
/* Special Member Functions */
OptionDouble() = default;
+ explicit OptionDouble(bool allow_trailing_data) :
+ allow_trailing_data_(allow_trailing_data)
+ {}
explicit(false) operator const QString& () const
{
return value_;
}
- void init(const QString& id, bool allow_trailing_data, int /* base */) override;
+ void init(const QString& id) override;
void reset() override;
void set(const QString& s) override;
+ bool isValid(const QString& s) const;
double get_result(QString* end = nullptr) const;
+ bool trailing_data_allowed() const;
private:
QString value_;
OptionString wptbgcolor;
OptionBool pack_opt;
int datum{};
- OptionDouble proximityarg;
+ OptionDouble proximityarg{true};
double proximity{};
OptionString altunit_opt;
OptionString proxunit_opt;
},
{
"proximity", &proximityarg, "Proximity distance",
- "0", ARGTYPE_ALLOW_TRAILING_DATA | ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+ "0", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
},
{
"altunit", &altunit_opt, "Unit used in altitude values",
double pos_dist{};
qint64 max_diff_time{};
- OptionDouble distopt;
+ OptionDouble distopt{true};
OptionDouble timeopt;
OptionBool purge_duplicates;
bool check_time{};
QVector<arglist_t> args = {
{
"distance", &distopt, "Maximum positional distance",
- nullptr, ARGTYPE_ALLOW_TRAILING_DATA | ARGTYPE_STRING | ARGTYPE_REQUIRED, ARG_NOMINMAX, nullptr
+ nullptr, ARGTYPE_STRING | ARGTYPE_REQUIRED, ARG_NOMINMAX, nullptr
},
{
"all", &purge_duplicates,
/* Data Members */
double pos_dist{};
- OptionDouble distopt;
+ OptionDouble distopt{true};
OptionDouble latopt;
OptionDouble lonopt;
OptionBool exclopt;
QVector<arglist_t> args = {
{
- "lat", &latopt, "Latitude for center point (D.DDDDD)",
+ "lat", &latopt, "Latitude for center point (D.DDDDD)",
nullptr, ARGTYPE_FLOAT | ARGTYPE_REQUIRED, ARG_NOMINMAX, nullptr
},
{
- "lon", &lonopt, "Longitude for center point (D.DDDDD)",
+ "lon", &lonopt, "Longitude for center point (D.DDDDD)",
nullptr, ARGTYPE_FLOAT | ARGTYPE_REQUIRED, ARG_NOMINMAX, nullptr
},
{
"distance", &distopt, "Maximum distance from center",
- nullptr, ARGTYPE_ALLOW_TRAILING_DATA | ARGTYPE_STRING | ARGTYPE_REQUIRED, ARG_NOMINMAX, nullptr
+ nullptr, ARGTYPE_STRING | ARGTYPE_REQUIRED, ARG_NOMINMAX, nullptr
},
{
- "exclude", &exclopt, "Exclude points close to center",
+ "exclude", &exclopt, "Exclude points close to center",
nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
},
{
- "nosort", &nosort, "Inhibit sort by distance to center",
+ "nosort", &nosort, "Inhibit sort by distance to center",
nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
},
{
--- /dev/null
+radius(lat): conversion to double failed: conversion of "44x" failed due to unexpected trailing data "x".
--- /dev/null
+stack(depth): conversion to integer failed: invalid argument "b".
--- /dev/null
+gdb(bitscategory): conversion to integer failed: conversion of "0x2z" failed due to unexpected trailing data "z".
--- /dev/null
+csv(snlen): conversion to integer failed: invalid argument "a".
metric_t metric{metric_t::crosstrack};
OptionInt countopt;
- OptionDouble erroropt;
+ OptionDouble erroropt{true};
OptionBool xteopt;
OptionBool lenopt;
OptionBool relopt;
QVector<arglist_t> args = {
{
- "count", &countopt, "Maximum number of points in route",
+ "count", &countopt, "Maximum number of points in route",
nullptr, ARGTYPE_INT | ARGTYPE_BEGIN_REQ | ARGTYPE_BEGIN_EXCL, "1", nullptr, nullptr
},
{
"error", &erroropt, "Maximum error", nullptr,
- ARGTYPE_ALLOW_TRAILING_DATA | ARGTYPE_STRING | ARGTYPE_END_REQ | ARGTYPE_END_EXCL, "0", nullptr, nullptr
+ ARGTYPE_STRING | ARGTYPE_END_REQ | ARGTYPE_END_EXCL, "0", nullptr, nullptr
},
{
"crosstrack", &xteopt, "Use cross-track error (default)", nullptr,
--- /dev/null
+# test detection of invalid option values
+# this should cover static and dynamic filters and functions.
+${VALGRIND} "${PNAME}" -i geo -f ${REFERENCE}/geocaching.loc -x radius,lat=44x -o gpx -F /dev/null 2> ${TMPDIR}/badopt1.txt && {
+ echo "${PNAME} succeeded! (it shouldn't have with this input...)"
+}
+compare ${REFERENCE}/badopt1.txt ${TMPDIR}/badopt1.txt
+${VALGRIND} "${PNAME}" -i geo -f ${REFERENCE}/geocaching.loc -x stack,depth=b -o gpx -F /dev/null 2> ${TMPDIR}/badopt2.txt && {
+ echo "${PNAME} succeeded! (it shouldn't have with this input...)"
+}
+compare ${REFERENCE}/badopt2.txt ${TMPDIR}/badopt2.txt
+${VALGRIND} "${PNAME}" -i gdb,bitscategory=0x2z -f ${REFERENCE}/gdb-sample.gdb -o xcsv -F /dev/null 2> ${TMPDIR}/badopt3.txt && {
+ echo "${PNAME} succeeded! (it shouldn't have with this input...)"
+}
+compare ${REFERENCE}/badopt3.txt ${TMPDIR}/badopt3.txt
+${VALGRIND} "${PNAME}" -i gdb,bitscategory=0x2 -f ${REFERENCE}/gdb-sample.gdb -o csv,snlen=a -F /dev/null 2> ${TMPDIR}/badopt4.txt && {
+ echo "${PNAME} succeeded! (it shouldn't have with this input...)"
+}
+compare ${REFERENCE}/badopt4.txt ${TMPDIR}/badopt4.txt
* default initializer the default constructor would be implicitly deleted.
*/
-void Vecs::init_vec(Format* fmt)
+void Vecs::init_vec(Format* fmt, const QString& fmtname)
{
QVector<arglist_t>* args = fmt->get_args();
if (args && !args->isEmpty()) {
for (auto& arg : *args) {
if (arg.argval != nullptr) {
arg.argval->reset();
+ QString id = QStringLiteral("%1(%2)").arg(fmtname, arg.argstring);
+ arg.argval->init(id);
}
}
}
{
for (const auto& vec : d_ptr_->vec_list) {
if (vec.vec != nullptr) {
- init_vec(vec.vec);
+ init_vec(vec.vec, vec.name);
}
}
style_list = create_style_vec();
}
-int Vecs::integer_base(uint32_t argtype)
-{
- int base;
- switch (argtype & ARGTYPE_BASEMASK) {
- case ARGTYPE_BASE_AUTO:
- base = 0;
- break;
- case ARGTYPE_BASE_16:
- base = 16;
- break;
- case ARGTYPE_BASE_10:
- default:
- base = 10;
- }
- return base;
-
-}
-
-bool Vecs::trailing_data_allowed(uint32_t argtype)
-{
- return (argtype & ARGTYPE_ALLOW_TRAILING_DATA) == ARGTYPE_ALLOW_TRAILING_DATA;
-}
-
-bool Vecs::is_integer(const QString& val, const QString& id, uint32_t argtype)
-{
- bool ok;
- int base = integer_base(argtype);
- QString end;
- QString* endp = trailing_data_allowed(argtype) ? &end : nullptr;
- (void) parse_integer(val, id, &ok, endp, base);
- return ok;
-}
-
-bool Vecs::is_float(const QString& val, const QString& id, uint32_t argtype)
-{
- bool ok;
- QString end;
- QString* endp = trailing_data_allowed(argtype) ? &end : nullptr;
- (void) parse_double(val, id, &ok, endp);
- return ok;
-}
-
bool Vecs::is_bool(const QString& val)
{
return val.startsWith('y', Qt::CaseInsensitive) ||
}
arg.argval->reset();
- int base = integer_base(arg.argtype);
- bool allow_trailing_data = trailing_data_allowed(arg.argtype);
- arg.argval->init(id, allow_trailing_data, base);
if (val.isNull()) {
return;
}
#endif
for (const auto& arg : *args) {
- QString id = QStringLiteral("%1(%2)").arg(name, arg.argstring);
if (arg.argval == nullptr) {
Warning() << name << "option" << arg.argstring << "does not point to an Option instance.";
ok = false;
}
if (const auto* int_option = dynamic_cast<const OptionInt*>(arg.argval); int_option != nullptr) {
- if (trailing_data_allowed(arg.argtype)) {
+ if (int_option->trailing_data_allowed()) {
// GUI QIntValidator will reject input with trailing data.
if ((arg.argtype & ARGTYPE_TYPEMASK) != ARGTYPE_STRING) {
Warning() << name << "OptionInt with trailing data" << arg.argstring << "is not of ARGTYPE_STRING.";
}
}
- if (!arg.defaultvalue.isNull() && !is_integer(arg.defaultvalue, id, arg.argtype)) {
+ if (!arg.defaultvalue.isNull() && !int_option->isValid(arg.defaultvalue)) {
Warning() << name << "Int option" << arg.argstring << "default value" << arg.defaultvalue << "is not an integer.";
ok = false;
}
- if (!arg.minvalue.isNull() && !is_integer(arg.minvalue, id, arg.argtype)) {
+ if (!arg.minvalue.isNull() && !int_option->isValid(arg.minvalue)) {
Warning() << name << "Int option" << arg.argstring << "minimum value" << arg.minvalue << "is not an integer.";
ok = false;
}
- if (!arg.maxvalue.isNull() && !is_integer(arg.maxvalue, id, arg.argtype)) {
+ if (!arg.maxvalue.isNull() && !int_option->isValid(arg.maxvalue)) {
Warning() << name << "Int option" << arg.argstring << "maximum value" << arg.maxvalue << "is not an integer.";
ok = false;
}
} else if (const auto* double_option = dynamic_cast<const OptionDouble*>(arg.argval); double_option != nullptr) {
- if (trailing_data_allowed(arg.argtype)) {
+ if (double_option->trailing_data_allowed()) {
// GUI QDoubleValidator will reject input with trailing data.
if ((arg.argtype & ARGTYPE_TYPEMASK) != ARGTYPE_STRING) {
Warning() << name << "OptionDouble with trailing data" << arg.argstring << "is not of ARGTYPE_STRING.";
}
}
- if (!arg.defaultvalue.isNull() && !is_float(arg.defaultvalue, id, arg.argtype)) {
+ if (!arg.defaultvalue.isNull() && !double_option->isValid(arg.defaultvalue)) {
Warning() << name << "Float option" << arg.argstring << "default value" << arg.defaultvalue << "is not an float.";
ok = false;
}
- if (!arg.minvalue.isNull() && !is_float(arg.minvalue, id, arg.argtype)) {
+ if (!arg.minvalue.isNull() && !double_option->isValid(arg.minvalue)) {
Warning() << name << "Float option" << arg.argstring << "minimum value" << arg.minvalue << "is not an float.";
ok = false;
}
- if (!arg.maxvalue.isNull() && !is_float(arg.maxvalue, id, arg.argtype)) {
+ if (!arg.maxvalue.isNull() && !double_option->isValid(arg.maxvalue)) {
Warning() << name << "Float option" << arg.argstring << "maximum value" << arg.maxvalue << "is not an float.";
ok = false;
}
/* Member Functions */
- static void init_vec(Format* fmt);
+ static void init_vec(Format* fmt, const QString& fmtname);
void init_vecs();
static void free_options(QVector<arglist_t>* args);
static void exit_vec(Format* fmt);
/* Member Functions */
- static int integer_base(uint32_t argtype);
- static bool trailing_data_allowed(uint32_t argtype);
- static bool is_integer(const QString& val, const QString& id, uint32_t argtype);
- static bool is_float(const QString& val, const QString& id, uint32_t argtype);
static bool is_bool(const QString& val);
static QVector<style_vec_t> create_style_vec();
QVector<vecinfo_t> sort_and_unify_vecs() const;